# -*- coding: utf-8 -*-
import os, stat, errno
import fuse
import sys
from fuse import Fuse, Stat, FuseStruct, FuseInvalidate
from inode import Inode
import time
import pdb

class Simple_Direntry(FuseStruct):
    """
    Auxiliary class for carrying directory entry data.
    Initialized with 'name' and 'ino'.
    Further attributes:

    offset
            An integer (or long) parameter, used as a bookmark
            during directory traversal.
            This needs to be set it you want stateful directory
            reading.

    type
            Directory entry type, should be one of the stat type
            specifiers (stat.S_IFLNK, stat.S_IFBLK, stat.S_IFDIR,
            stat.S_IFCHR, stat.S_IFREG, stat.S_IFIFO, stat.S_IFSOCK).

    Note that Python's standard directory reading interface is
    stateless and provides only names, so the above optional
    attributes doesn't make sense in that context.
    """
    def __init__(self, name, offset, type, ino, **kw):
        self.name   = name
        self.offset = offset
        self.type   = type
        self.ino    = ino

        FuseStruct.__init__(self, **kw)

class Simple(Fuse):
    """
    Filesystem class. The principal task is manage the filesystem and
            administer the log.
            Note: The log can be deactive just not calling the function 'open_log'
    """
    def __init__(self, *argv, **kw):
        fuse.Fuse.__init__(self, *argv, **kw)
        # File descriptor for print.
        self.__fd = None
        # Loglvl of print.
        self.__loglvl = None
        # List of free ino number to assing
        self.__free_inonumber = []
        # Small ino number.
        self.__inonumber = 1
        # Table of path,inode.
        self.__table = {}


    def open_log(self, filename = None, loglvl = [1]):
        """
        His task is set the type and lvl of log.
        Default argument; filename = stdout, loglvl = [1]
        More:
                Filename; Can be any fd. only needed the absolut path.
                Loglvl; A list of levels: 1, 2 and 3 are the options.
        """
        if filename == None:
                self.__fd = sys.stdout
        else:
                self.__fd = open(filename, 'w')
        self.__loglvl = loglvl

    def debug1(self, format, *others):
        self.__debug(1,format,*others)

    def debug2(self, format, *others):
        self.__debug(2,format,*others)

    def debug3(self, format, *others):
        self.__debug(3,format,*others)

    def __debug(self,lvl,format,*others):
        if (self.__fd != None and self.__loglvl != None):
            if not (lvl in self.__loglvl) : return
            t = time.strftime("%a, %d %b %Y %H:%M:%S -0300", time.gmtime())
            self.__fd.write('[%s] ' % t)
            self.__fd.write((format + '\n') % others)
            self.__fd.flush()

    # Determined if an user has permission on a file.
    def __has_permission(self, path):
        # Take the inode from the table.
        inode = self.__table[path]
        # Take the uid.
        uid = fuse.os.getuid()
        if(uid == inode.metadata.st_uid):
            return True # If the user has permission on the file.
        else:
            return False # Otherwise.

    def __check_path_long(self,path):
        fname = path.rpartition('/')[2]
        return len (fname) > 255

    def getattr(self, path):
        self.debug1('Getattr-Entry: Path: %s', path)
        # If path is root.
        if (path == '/'):
            st = Stat()
            st.st_mode = stat.S_IFDIR | 0755
            st.st_nlink = 2
        # Else check the file exist.
        elif (self.__table.has_key(path)):
            st = self.__table[path].metadata
        else:
            st = -errno.ENOENT
        self.debug1('Getattr-Exit: St: %s', st)
        return st

    def mknod(self, path, mode, dev):
        self.debug1('Mknod-Entry: Path: %s, Mode: %s, Dev: %s', path, mode, dev)
        self.debug1('Mknod-Entry: Not implemented')
        self.debug1('Mknod-Exit: %s', 0)
        return 0

    def readdir(self, path, offset):
        self.debug1('Readdir-Entry: Path: %s, Offset: %s', path, offset)
        self.debug1('Readdir-Entry: Not implemented')
        result = {}
        self.debug1('Readdir-Exit: Collected list of path\'s: %s', result)
        
    def write(self, path, buff, offset):
        self.debug1('Write-Entry: Path: %s, Offset: %s', path, offset)
        self.debug1('Write-Entry: Not implemented')
        rt = len (buff)
        self.debug1('Write-Exit: Ret: %s', rt)
        return rt

    def read (self, path, length, offset):
        self.debug1('Read-Entry: Path: %s, Lenght: %s, Offset: %s', path, length, offset)
        self.debug1('Read-Entry: Not implemented')
        buff = ""
        rt = buff
        prt = len(buff)
        self.debug1('Read-Exit: Ret: %s', prt)
        return rt

    def utime (self, path, times):
        self.debug1('Utime-Entry: Path: %s, Times: %s', path, times)
        self.debug1('Utime-Entry: Not implemented')
        self.debug1('Utime-Exit: Ret: %s', 0)
        return 0

    def mkdir(self, path, mode):
        self.debug1('Mkdir-Entry: Path: %s, Mode: %s', path, mode)
        self.debug1('Mkdir-Entry: Not implemented')
        self.debug1('Mkdir-Exit: Ret: %s', 0)
        return 0

    def rmdir(self, path):
        self.debug1('Rmdir-Entry: Path: %s', path)
        self.debug1('Rmdir-Entry: Not implemented')
        self.debug1('Rmdir-Exit: Ret: %s', 0)
        return 0

    def unlink (self, path):
        self.debug1('Unlink-Entry: Path: %s', path)
        self.debug1('Unlink-Entry: Not implemented')
        self.debug1('Unlink-Exit: Ret: %s', 0)
        return 0

    def rename (self, current_path, new_path):
        self.debug1('Rename-Entry: Current_Path: %s, New_Path: %s', current_path, new_path)
        self.debug1('Not implemented')
        self.debug1('Rename-Exit: Ret: %s', 0)
        return 0

    def chmod (self, path, mode):
        self.debug1('Chmod-Entry: Path: %s, Mode: %s', path, mode)
        self.debug1('Chmod-Entry: Not implemented')
        self.debug1('Chmod-Exit: Ret: %s', 0)
        return 0

    def chown (self, path, uid, gid):
        self.debug1('Chown-Entry: Path: %s, Uid: %s, Gid: %s', path, uid, gid)
        self.debug1('Chown-Entry: Not implemented')
        self.debug1('Chown-Exit: Ret: %s', 0)
        return 0

    def truncate (self, path, new_size):
        self.debug1('Truncate-Entry: Path: %s, New_Size: %s', path, new_size)
        self.debug1('Truncate-Entry: Not implemented')
        self.debug1('Truncate-Exit: Ret: %s', 0)
        return 0

    def readlink (self, path):
        self.debug1('Readlink: path: %s', path)
        self.debug1('Readlink: Not implemented')
        rt = ""
        self.debug1('Readlink-Exit: Ret: %s', rt)
        return rt

    def symlink (self, target, name):
        self.debug1('Symlink-Entry: Target: %s, name: %s', target, name)
        self.debug1('Symlink-Entry: Not implemented')
        self.debug1('Symlink-Exit: Ret: %s', 0)
        return 0

    def link (self, target, name):
        self.debug1('Hardlink-Entry: Target: %s, name: %s', target, name)
        self.debug1('Hardlink-Entry: Not implemented')
        self.debug1('Hardlink-Exit: Ret: %s', 0)
        return 0

    def statfs(self):
        self.debug1('Statfs-Entry')

        result = fuse.StatVfs()

        self.debug1('Statfs-Entry: Not implemented')
        
        self.debug1('Statfs-Exit: Ret: %s', result)
        return result
